using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using Rhizome.Bindings;
using Rhizome.Contract;
using Rhizome.Contract.Diag;
using Rhizome.Internal;
using Rhizome.Model.Validation;

namespace Rhizome.Model
{
	/// <summary>
	/// 	Property trigger
	/// </summary>
	/// <typeparam name = "TProperty"></typeparam>
	public class Trigger<TProperty> : TriggerBase<INotifyPropertyChanged>, IForwardEvent
	{
		/// <summary>
		/// 	Plant Property name.
		/// 	If not set Trigger will trigged at any Property changes
		/// </summary>
		public string Property
		{
			get
			{
				var b = Binding;
				return b == null ? null : b.Property;
			}
			set { SetValue(BindingProperty, BindingProxy.Create(value)); }
		}

		private BindingProxy Binding
		{
			[DebuggerStepThrough]
			get { return GetValue(BindingProperty); }
		}

		/// <summary>
		/// 	XAML "macro".
		/// 	Sets Criterion to IfEquals(Property, value) criterion. Must be set after Property
		/// </summary>
		public virtual TProperty Value
		{
			get
			{
				var c = Criterion as IfEquals<TProperty>;
				return c == null ? default(TProperty) : c.Value;
			}
			set
			{
				Criterion =
					typeof (TProperty) == typeof (object)
						? (ICriterion) new IfEquals {Value = value}
						: new IfEquals<TProperty> {Value = value};
			}
		}

		public override void Initialize()
		{
			Binding.PropertyChanged += PlantOnPropertyChanged;
		}

		public override void Cleanup()
		{
			Binding.PropertyChanged -= PlantOnPropertyChanged;
		}

		private void PlantOnPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			Trigged();
		}

		#region Validation

		public override IEnumerable<IValidationResult> GetValidationResults()
		{
			return base.GetValidationResults().Concat(InternalValidate());
		}

		private IEnumerable<IValidationResult> InternalValidate()
		{
			if (Plant == null) yield return ValidationResult.PlantIsNull;
			if (Property.IsNullOrEmpty()) yield return ValidationResult.PropertyNotSetWarning;
		}

		#endregion
	}

	public sealed class Trigger : Trigger<object>
	{
		#region Overrides of Trigger<object>

		/// <summary>
		/// XAML "macro".
		/// Sets criterion to Property == value using CriterionTypeConverter
		/// </summary>
		public override object Value
		{
			[DebuggerStepThrough]
			get { return null; }
			set { Criterion = CriterionTypeConverter.ParseCriterion("{0}=={1}".With(Property, value)); }
		}

		#endregion
	}
}